using System;
using System.Reflection;
using System.Collections.Generic;

namespace Elephant.Framework
{
    /// <summary>
    /// Represents a factory that instantiates component objects and assigns them an owner.
    /// </summary>
    public sealed class ComponentFactory : Factory
    {
        /// <summary>
        /// Creates a component of the given type with the specified parameters, overwriting any existing components of the same type if specified.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="owner"></param>
        /// <param name="overwrite"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static EntityComponent Create(Type type, Entity owner, bool overwrite, params object[] parameters)
        {
            ConstructorInfo bestMatch = GetBestMatchingConstructor(type, parameters);

            object o = null;

            try {
                o = bestMatch.Invoke(parameters);
            } catch (TargetParameterCountException tpce) {
                throw tpce;
            }

            EntityComponent component = o as EntityComponent;

            component.Owner = owner;
            owner.Add(component, overwrite);

            return o as EntityComponent;
        }

        /// <summary>
        /// Creates a component of type T.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="owner"></param>
        /// <returns></returns>
        public static T Create<T>(Entity owner) where T : EntityComponent
        {
            return Create<T>(owner, new object[] { });
        }

        /// <summary>
        /// Creates a component of type T with the specified parameters.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="owner"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static T Create<T>(Entity owner, params object[] parameters) where T : EntityComponent
        {
            return Create<T>(owner, false, parameters);
        }

        /// <summary>
        /// Creates a component of type T with the specified parameters, overwriting any existing components if specified.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="owner"></param>
        /// <param name="overwrite"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static T Create<T>(Entity owner, bool overwrite, params object[] parameters) where T : EntityComponent
        {
            ConstructorInfo bestMatch = GetBestMatchingConstructor(typeof(T), parameters);

            object o = null;

            try {
                o = bestMatch.Invoke(parameters);
            } catch (TargetParameterCountException tpce) {
                throw tpce;
            }

            EntityComponent component = o as EntityComponent;

            component.Owner = owner;
            owner.Add(component, overwrite);

            return o as T;
        }
    }
}
